準備技術:
當Java Class進入到JVM,是以Bytecode格式進入,ASM的目的是希望能夠修改Bytecode或動態產生Class。為什麼要修改Class?因為有這樣的機制,我們可以動態的將Clas加料,這是依賴注入。
如圖,針對Spring Container我們可以注入MetaData和POJO資料改變一些Class的結果,達到另一個功能實現的目的。
先看一個例子,我們想要寫一個Class觀看另一個Class的變數。變數有Static的,final的,以及非Static或Final的如String,還有double。
public class ForReadClass {
final int init = 110;
private final Integer intField = 120;
public final String stringField = "Public Final Strng Value";
public static String commStr = "Common String value";
String str = "Just a string value";
final double d = 1.1;
final Double D = 1.2;
public ForReadClass() {
}
public void methodA() {
System.out.println(intField);
}
@SuppressWarnings("unchecked")
public static void main(String[] args) {
try { ClassReader reader = new ClassReader("core.ForReadClass");
ClassNode cn = new ClassNode(); reader.accept(cn, 0);
System.out.println(cn.name); List<FieldNode> fieldList = cn.fields;
for (FieldNode fieldNode : fieldList) {
System.out.println("Field name: " + fieldNode.name);
System.out.println("Field desc: " + fieldNode.desc);
System.out.println("Filed value: " + fieldNode.value);
System.out.println("Filed access: " + fieldNode.access); }
} catch(IOException e)
{ e.printStackTrace(); }
}
}
程式執行之後,很明顯的,沒有抓到 非Static或Final系列的變數。
利用ASM的AbstractInNode方式抓到全部變數而看到,但是經由測試,Double變數沒抓到,這以後修改。
public static void main(String[] args) {
try {
ClassReader reader = new ClassReader("core.ForReadClass");
ClassNode cn = new ClassNode();
reader.accept(cn, 0);
List<MethodNode> methodList = cn.methods;
for (MethodNode md : methodList) {
System.out.println(md.name);
System.out.println(md.access);
System.out.println(md.desc);
System.out.println(md.signature);
List<LocalVariableNode> lvNodeList = md.localVariables;
for (LocalVariableNode lvn : lvNodeList) {
System.out.println("Local name: " + lvn.name);
System.out.println("Local name: " + lvn.start.getLabel());
System.out.println("Local name: " + lvn.desc);
System.out.println("Local name: " + lvn.signature);
}
Iterator<AbstractInsnNode> instraIter = md.instructions.iterator();
while (instraIter.hasNext()) {
AbstractInsnNode abi = instraIter.next();
if (abi instanceof LdcInsnNode) {
LdcInsnNode ldcI = (LdcInsnNode) abi;
System.out.println("LDC node value: " + ldcI.cst);
}
}
}
MethodVisitor mv = cn.visitMethod(Opcodes.AALOAD, "<init>", Type
.getType(String.class).toString(), null, null);
mv.visitFieldInsn(Opcodes.GETFIELD,
Type.getInternalName(String.class), "str",
Type.getType(String.class).toString());
System.out.println(cn.name);
List<FieldNode> fieldList = cn.fields;
for (FieldNode fieldNode : fieldList) {
System.out.println("Field name: " + fieldNode.name);
System.out.println("Field desc: " + fieldNode.desc);
System.out.println("Filed value: " + fieldNode.value);
System.out.println("Filed access: " + fieldNode.access);
/*
if (fieldNode.visibleAnnotations != null) {
for (AnnotationNode anNode : fieldNode.visibleAnnotations) {
System.out.println(anNode.desc);
}
}
*/
}
} catch (IOException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
參考書籍:
Day 24 結束